export class LinkNode<T> {
    public next: LinkNode<T>;
    public prev: LinkNode<T>;
    public data: T | undefined;

    public constructor ( data: T | undefined = undefined ) {
        this.next = this.prev = this;
        this.data = data;
    }

    public link ( newLink: LinkNode<T>, append: boolean = true ): void {
        // 后面
        if ( append === true ) {
            newLink.next = this;
            newLink.prev = this.prev;
            this.prev.next = newLink;
            this.prev = newLink;
        } else {
            //前面
            newLink.prev = this;
            newLink.next = this.next;
            this.next.prev = newLink;
            this.next = newLink;
        }
    }

    public unlink (): void {
        if ( this.next !== null ) {
            this.next.prev = this.prev;
        }
        if ( this.prev !== null ) {
            this.prev.next = this.next;
        }
    }
}

export class LinkList<T> {
    private _header: LinkNode<T>;
    private _count: number;

    public constructor () {
        this._header = new LinkNode();
        this._count = 0;
    }

    public get length (): number {
        return this._count;
    }

    public push ( item: T ): LinkNode<T> {
        let n: LinkNode<T> = new LinkNode( item );
        this._header.link( n );
        this._count++;
        return n;
    }

    public pop (): T | undefined {
        if ( this._header.prev === this._header ) {
            return undefined;
        }

        let data: T | undefined = this._header.prev.data;
        this._header.prev.unlink();
        this._count--;
        return data;
    }

    // 这个目前有问题，next和prev有不正确性
    public insertAfter ( node: LinkNode<T>, data: T | undefined ): LinkNode<T> {
        let temp: LinkNode<T> = new LinkNode<T>( data );
        temp.next = node;
        temp.prev = node.prev;
        node.prev.next = temp;
        node.prev = temp;
        this._count++;
        return temp;
    }

    public contains ( item: T ): boolean {
        for ( let link: LinkNode<T> = this._header.next; link != this._header; link = link.next ) {
            if ( link.data !== undefined ) {
                if ( link.data === item ) {
                    return true;
                }
            }
        }
        return false;
    }

    public forNext ( cb: ( data: T ) => void ): void {
        for ( let link: LinkNode<T> = this._header.next; link != this._header; link = link.next ) {
            if ( link.data !== undefined ) {
                cb( link.data );
            }
        }
    }

    public forPrev ( cb: ( data: T ) => void ): void {
        for ( let link: LinkNode<T> = this._header.prev; link != this._header; link = link.prev ) {
            if ( link.data !== undefined ) {
                cb( link.data );
            }
        }
    }
}

/*
let list:LinkList<number> = new LinkList();
        list.push(0);
        list.push(1);
        list.push(2);

        list.pop();

        list.forNext((data:number):void =>{
            console.log(data);
        });

        list.forPrev((data:number):void =>{
            console.log(data);
        });
*/